BLE 路线传输与运动数据同步深挖
BLE 路线传输与运动数据同步深挖
为巽1. ESP-Hosted BLE 架构
P4 关闭本地 Bluetooth Controller,运行 NimBLE Host/GATT Server;C6 提供 Controller,HCI 通过 ESP-Hosted VHCI over SDIO。P4 上的 bt/app_ble.c 负责广播、连接和 notify,app_ble_gatt.c 定义 characteristic,app_ble_proto.c 解析统一包头,业务数据再进入各自 task。
设备名 Aero-Wtach,单连接,preferred MTU=247,Legacy connectable advertising。Ride Service 下有 Live Metrics、Command、Config、Ride Record、Route Status;另注册标准 Battery Service。
2. 通用 Command
1 | cmd_id:u8 | seq:u8 | payload_len:u8 | payload[payload_len] |
实际长度必须等于 3+payload_len,写缓存上限 128 B。seq 只用于日志,不能当 ACK、时间戳或去重依据。GATT 层先做长度、版本、flags 和范围校验,业务成功以对应状态/快照为准。
3. 完整路线 0x22~0x25
V1:普通 Cycling,8 B/点;V2:显式 activity_type,12 B/点,增加 altitude_cm,MTB 必须用 V2。点数 2~2048,最大数据 24576 B,坐标固定 GCJ-02。
BEGIN
V1 payload 16 B:version、coordinate_system、route_id、point_count、total_length、crc32。V2 payload 18 B,在头部增加 activity_type 和 point_format。有效 BEGIN 会释放旧接收缓冲,PSRAM 申请完整数据区,状态变为 RECEIVING。
DATA
payload 含 version、route_id、offset 和 1~116 B data。设备只接受 offset == received_length;相同 offset 且字节内容完全一致允许重复发送,跳 offset、越界或内容不同返回 INVALID_OFFSET。116 B 是协议上限,实际还受 negotiated_mtu-15 限制。
COMMIT
只有收到总长度后才计算 CRC32(多项式 0xEDB88320,初值/异或 0xFFFFFFFF)。CRC 正确后一次性解析所有点、校验纬度/经度范围,生成点数组和最多 64 点的归一化缩略图,再在 mutex 内替换 LOADED 快照。接收缓冲和点数组短时并存,V2 峰值约 49 KiB,不含地图投影。
ABORT/断开
ABORT 只释放未完成传输,不清除已 LOADED 路线;断 BLE 会中止接收但保留已加载路线。0x21 才清除完整路线和旧途经点路线。Route Status 固定 20 B,包含 state/error/route_id/received/total/point_count/generation,支持 Read/Notify。
4. PHONE 定位 0x30
24 B payload:version、flags、timestamp_ms、lat/lon e7、altitude cm、speed cm/s、course 0.1°、accuracy cm。最小有效 flags 是经纬度+精度。GATT callback 只解析后投递长度 4 的队列;phone_location_task 检查 accuracy<=50 m、时间戳单调、跳点和 3 s 超时,再调用运动模型。
运行状态下才累计距离和时间。路线存在时,PHONE GCJ-02 先转 WGS84,再投影到路线,更新 route_progress_cm。BLE 断开不跨断连时间累计,定位模式不会自动回退 DEMO。
5. Live Metrics 与历史记录
Live Metrics 每 1 s notify,固定 17 B:elapsed_s、distance_m、speed_x100、avg_speed_x100,电池字段目前是保留值;真实电量走 Battery Level。完整历史不复用实时包,而使用 Ride Record characteristic:记录 payload v2 固定 99 B,新增 route_id;包头 11 B,默认 MTU 23 时每分包 9 B,另有 CRC 完成、同步完成和删除标记包。
记录 SAVE 后先写 ride_history NVS,状态 pending;小程序完整校验后发 0x41(record_id) 才变 synced。0x40 flags 可请求最新、pending、删除标记;0x42 请求重传。删除标记最多 32 条,跨断线和重启保留。
6. 时间和天气
0x02 用 UTC Unix 秒+时区分钟更新统一时间快照,不写 Flash;0x10 固定 58 B,由天气 task 更新快照,数据变化时才写 NVS。两者都要求有响应 Write,业务成功不是“写入 API 返回”,而是任务更新后的状态/generation。
7. 面试追问
为什么完整路线不用单个 GATT Write? MTU 和写缓存有限,分包允许断点续传和 CRC 完整性校验;offset 严格递进避免乱序覆盖。
为什么 Route Status 不增加 activity_type? 保持 20 B 旧客户端兼容,activity_type 保存在终端内部快照,Cycling/MTB 通过内部匹配消费。
GATT Write 成功是否代表路线成功? 不是,只代表包通过同步校验并进入队列;必须等待 Route Status LOADED。
1 |



